﻿using Modbus.Messages;

namespace Modbus
{
	partial class ModbusClient
	{
		public short[] ReadHoldingRegisters(byte slaveAddress, int startingAddress, int quantity)
		{
			//
			// Input arguments validation.
			//
			
			Ensure.ArgumentNotEqualTo(SR.Argument_slaveAddress, slaveAddress, BroadcastAddress);
			Ensure.ArgumentInRange(SR.Argument_startingAddress, startingAddress, MinDataAddress, MaxDataAddress);
			Ensure.ArgumentInRange(SR.Argument_quantity, quantity, ModbusSpecification.MinQuantity,
				ModbusSpecification.ReadHoldingRegistersMaxQuantity);

			//
			//
			//

			return this.ReadRegisters(FunctionCodes.ReadHoldingRegisters, slaveAddress, (ushort)(startingAddress),
				(ushort)(quantity));
		}

		public short[] ReadInputRegisters(byte slaveAddress, int startingAddress, int quantity)
		{
			//
			// Input arguments validation.
			//
			
			Ensure.ArgumentNotEqualTo(SR.Argument_slaveAddress, slaveAddress, BroadcastAddress);
			Ensure.ArgumentInRange(SR.Argument_startingAddress, startingAddress, MinDataAddress, MaxDataAddress);
			Ensure.ArgumentInRange(SR.Argument_quantity, quantity, ModbusSpecification.MinQuantity,
				ModbusSpecification.ReadInputRegistersMaxQuantity);

			//
			//
			//

			return this.ReadRegisters(FunctionCodes.ReadInputRegisters, slaveAddress, (ushort)(startingAddress),
				(ushort)(quantity));
		}

		private short[] ReadRegisters(byte functionCode, byte slaveAddress, ushort startingAddress, ushort quantity)
		{
			//
			// Internal state validation.
			//

			this.ThrowIfDisposed();

			//
			// Request creation.
			//

			StartingAddressQuantityMessage request = new StartingAddressQuantityMessage();

			request.FunctionCode = functionCode;
			request.StartingAddress = startingAddress;
			request.Quantity = quantity;

			//
			// Perform transaction.
			//

			var response = this.transport.Request<ReadDataResponse>(slaveAddress, request);

			//
			// Response validation.
			//

			int excpectedByteCount = (2 * request.Quantity);

			if (response.Data.Length != excpectedByteCount)
			{
				throw new MismatchResponseException(SR.ModbusMessageField_ByteCount);
			}

			//
			// Prepare return value.
			//

			short[] registers = DataUtility.DecodeRegisters(response.Data);

			return registers;
		}
	}
}
